unit fMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls , uNeuralNetwork, uMatrix, ExtCtrls, ActnList, ComCtrls;

type

  TSaveParams = class
  private

  public
    Eta         : Double ;
    Epoca       : Integer ;
    Momento     : Double ;
    SizeInput   : Integer ;
    SizeLayer1  : Integer ;
    SizeLayer2  : Integer ;
    BiasLayer1  : String ;
    BiasLayer2  : String ;
    WLayer1     : String ;
    WLayer2     : String ;
    MaxIt       : Integer ;

    procedure SetParams ( PNN : TNeuralNetwork ) ;

  end;


  TForm1 = class(TForm)
    btnSalvarRedeAtual: TButton;
    actlst: TActionList;
    actSaveNN: TAction;
    actSaveBestNN: TAction;
    dlgSave: TSaveDialog;
    btnLoadNN: TButton;
    actLoadNN: TAction;
    dlgOpen: TOpenDialog;
    pc: TPageControl;
    tsLog: TTabSheet;
    tsParameters: TTabSheet;
    tsLogTeste: TTabSheet;
    edEta: TLabeledEdit;
    edMu: TLabeledEdit;
    edEpocas: TLabeledEdit;
    edTamanhoEntrada: TLabeledEdit;
    edNLayer1: TLabeledEdit;
    edNLayer2: TLabeledEdit;
    btnTreinar: TButton;
    btnTestar: TButton;
    btnGerarBase: TButton;
    actTreinar: TAction;
    actTestar: TAction;
    actGerarBase: TAction;
    memoTreino: TMemo;
    memoTeste: TMemo;
    btnNewNN: TButton;
    actNewNN: TAction;
    edMaxIteracoes: TLabeledEdit;
    tsBase: TTabSheet;
    btnImgToTxt: TButton;
    edtImgWidth: TEdit;
    edtImgHeight: TEdit;
    imgLetter: TImage;
    memoValidacao: TMemo;
    btnStrecher: TButton;
    img: TImage;
    btn1: TButton;
    procedure btn1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure btnImgToTxtClick(Sender: TObject);
    procedure actSaveNNExecute(Sender: TObject);
    procedure btnSalvarMelhorRedeClick(Sender: TObject);
    procedure actLoadNNExecute(Sender: TObject);
    procedure actTreinarExecute(Sender: TObject);
    procedure actNewNNExecute(Sender: TObject);
    procedure actTestarExecute(Sender: TObject);
    procedure btnStrecherClick(Sender: TObject);
  private
    NN  : TNeuralNetwork ;
    x   : TMatrix;
    t   : TMatrix;

    SaveParams  : TSaveParams ;


    FSizeInput  : Integer ;
    FSizeLayer1 : Integer ;
    FSizeLayer2 : Integer ;
    FEta        : Double  ;
    FEpoca      : Integer ;
    FMomento    : Double  ;
    FIterations : Integer ;

    ContadorGlobal : Integer ;

    procedure SalvaIni ( Path : String ) ;
    procedure LoadIni  ( Path : String ) ;

    procedure GetNNParams ;

    function ColorToRGBstring(Color: TColor): string;

  public
  end;



var
  Form1: TForm1;

implementation
uses
  Math, FileOperations, IniFiles , uImageInfo;
{$R *.dfm}

procedure TForm1.btn1Click(Sender: TObject);
var
  Bmp   : TBitmap ;
  i     : Integer ;
  List  : TList ;
  Path  : String ;
begin
  List  := nil;
  Bmp   := TBitmap.Create ;

  Path  := 'C:\Documents and Settings\arabe\Desktop\captcha.bmp' ;

  Bmp.LoadFromFile ( Path );

  TImageInfo.FilterAndSplit ( Bmp , List );

  FreeAndNil ( Bmp ) ;

  for i := 0 to List.Count - 1 do
  begin
    Bmp := TBitmap ( List[i] ) ;
    Bmp.SaveToFile ( ChangeFileExt ( Path , '_'+IntToStr ( i )+'.bmp' ) );
    Bmp.Free ;
  end;

  FreeAndNil ( List );

end;

function TForm1.ColorToRGBstring(Color: TColor): string;
var
  R,G,B : Integer; 
begin 
  result:=''; 
  R := Color and $ff; 
  G := (Color and $ff00) shr 8; 
  B := (Color and $ff0000) shr 16; 
  result := 'red:' + inttostr(r) + ' green:' + inttostr(g) + ' blue:' + inttostr(b); 
end;

procedure TForm1.FormCreate(Sender: TObject);
begin

  NN  := TNeuralNetwork.Create ( 20*20 , 20 , 9 , 0.001/108, 0.0) ;

  x := TMatrix.Create(2, 1);
  t := TMatrix.Create(1, 1);

  SaveParams  := TSaveParams.Create ;

  Randomize;

end;


procedure TForm1.btnImgToTxtClick(Sender: TObject);
var
  bmp, bmp2 : TBitmap;

  arect      : TRect;

  i,
  c, r        : Integer;

  Line      : string;

  Filename  : string;

  InFileStringList  : TStringList;

  Files             : TStringList;

begin
  arect.TopLeft := Point(0, 0);
  arect.BottomRight := Point(20, 20);

  bmp := TBitmap.Create;
  bmp2 := TBitmap.Create;
  InFileStringList := TStringList.Create;

  Files := TFileOperator.ListFiles(ExtractFilePath(ParamStr(0)) + 'treino\', '*.bmp');
  
  for i := 0 to Files.Count-1 do
    begin
      Filename := Files[i];
      
      bmp.LoadFromFile('treino\' + Filename);

      bmp.Canvas.StretchDraw(arect, bmp);
      bmp2.Assign(bmp);

      bmp2.Width := StrToInt(edtImgWidth.Text);
      bmp2.Height := StrToInt(edtImgHeight.Text);

      Line := '';
      for r := 0 to bmp2.Height-1 do
        begin
          for c := 0 to bmp2.Width-1 do
            begin
              if bmp2.Canvas.Pixels[c, r] <> clwhite then
                Line := Line + '1;'
              else
                Line := Line + '-1;';

            end;
        end;

      Line := Line + '?';
      
      for r := 1 to 9 do
        begin
          if (IntToStr(r) = Copy(Filename, 1, 1)) then
            Line := Line + '1;'
          else
            Line := Line + '-1;';
        end;
      InFileStringList.Add(Line);
    end;
    
  InFileStringList.SaveToFile('treino\infile.rni');
  InFileStringList.Clear;

  FreeAndNil(Files);

  Files := TFileOperator.ListFiles(ExtractFilePath(ParamStr(0)) + 'validacao\', '*.bmp');

  for i := 0 to Files.Count-1 do
    begin
      Filename := Files[i];

      bmp.LoadFromFile('validacao\' + Filename);

      bmp.Canvas.StretchDraw(arect, bmp);
      bmp2.Assign(bmp);

      bmp2.Width := StrToInt(edtImgWidth.Text);
      bmp2.Height := StrToInt(edtImgHeight.Text);

      Line := '';
      for r := 0 to bmp2.Height-1 do
        begin
          for c := 0 to bmp2.Width-1 do
            begin
              if bmp2.Canvas.Pixels[c, r] <> clwhite then
                Line := Line + '1;'
              else
                Line := Line + '-1;';

            end;
        end;

      Line := Line + '?';
      
      for r := 1 to 9 do
        begin
          if (IntToStr(r) = Copy(Filename, 1, 1)) then
            Line := Line + '1;'
          else
            Line := Line + '-1;';
        end;
      InFileStringList.Add(Line);
    end;
    
  InFileStringList.SaveToFile('validacao\validfile.rni');
  InFileStringList.Clear;

  FreeAndNil(Files);

  Files := TFileOperator.ListFiles(ExtractFilePath(ParamStr(0)) + 'teste\', '*.bmp');
  
  for i := 0 to Files.Count-1 do
    begin
      Filename := Files[i];

      bmp.LoadFromFile('teste\' + Filename);

      bmp.Canvas.StretchDraw(arect, bmp);
      bmp2.Assign(bmp);

      bmp2.Width := StrToInt(edtImgWidth.Text);
      bmp2.Height := StrToInt(edtImgHeight.Text);

      Line := '';
      for r := 0 to bmp2.Height-1 do
        begin
          for c := 0 to bmp2.Width-1 do
            begin
              if bmp2.Canvas.Pixels[c, r] <> clwhite then
                Line := Line + '1;'
              else
                Line := Line + '-1;';

            end;
        end;

      Line := Line + '?';
      
      for r := 1 to 9 do
        begin
          if (IntToStr(r) = Copy(Filename, 1, 1)) then
            Line := Line + '1;'
          else
            Line := Line + '-1;';
        end;
      InFileStringList.Add(Line);
    end;
    
  InFileStringList.SaveToFile('teste\testfile.rni');
  InFileStringList.Clear;

  FreeAndNil(Files);
  FreeAndNil(InFileStringList);

end;

procedure TForm1.actSaveNNExecute(Sender: TObject);
begin
  if not dlgSave.Execute then
    exit;

  SaveParams.SetParams ( NN );

  SalvaIni ( dlgSave.FileName ) ;

end;

{ TSaveParams }

procedure TSaveParams.SetParams(PNN: TNeuralNetwork);
var
  i , j   : Integer ;
begin
  SizeInput       := PNN.SizeInput ;
  SizeLayer1      := PNN.SizeLayer1 ;
  SizeLayer2      := PNN.SizeLayer2 ;

  Eta := PNN.Eta ;
  Momento := PNN.Mu ;

  for i := 0 to PNN.BiasLayer1.RowCount - 1 do
  begin
    for j := 0  to PNN.BiasLayer1.ColCount - 1 do
    begin
      if ( ( i = 0 ) and ( j = 0 ) ) then
        BiasLayer1  := FloatToStr (PNN.BiasLayer1[i,j])
      else
        BiasLayer1  := BiasLayer1 + ';' + FloatToStr (PNN.BiasLayer1[i,j]) ;
    end;
  end;

  for i := 0 to PNN.BiasLayer2.RowCount - 1 do
  begin
    for j := 0  to PNN.BiasLayer2.ColCount - 1 do
    begin
      if ( ( i = 0 ) and ( j = 0 ) ) then
        BiasLayer2  := FloatToStr (PNN.BiasLayer2[i,j])
      else
        BiasLayer2  := BiasLayer2 + ';' + FloatToStr (PNN.BiasLayer2[i,j]) ;
    end;
  end;

  for i := 0 to PNN.WeightsLayer1.RowCount - 1 do
  begin
    for j := 0  to PNN.WeightsLayer1.ColCount - 1 do
    begin
      if ( ( i = 0 ) and ( j = 0 ) ) then
        WLayer1  := FloatToStr (PNN.WeightsLayer1[i,j])
      else
        WLayer1  := WLayer1 + ';' + FloatToStr (PNN.WeightsLayer1[i,j]) ;
    end;
  end;

  for i := 0 to PNN.WeightsLayer2.RowCount - 1 do
  begin
    for j := 0  to PNN.WeightsLayer2.ColCount - 1 do
    begin
      if ( ( i = 0 ) and ( j = 0 ) ) then
        WLayer2  := FloatToStr (PNN.WeightsLayer2[i,j])
      else
        WLayer2  := WLayer2 + ';' + FloatToStr (PNN.WeightsLayer2[i,j]) ;
    end;
  end;

end;

procedure TForm1.SalvaIni(Path: String);
var
  IniFile : TextFile ;
begin

  AssignFile(IniFile, Path );
  Rewrite(IniFile);
  WriteLn(IniFile, IntToStr ( SaveParams.SizeInput ) ) ;
  WriteLn(IniFile, IntToStr (  SaveParams.SizeLayer1) ) ;
  WriteLn(IniFile, IntToStr (  SaveParams.SizeLayer2) ) ;

  WriteLn(IniFile,  FloatToStr ( SaveParams.Eta) );
  WriteLn(IniFile,  FloatToStr ( SaveParams.Momento) ) ;
  WriteLn(IniFile,  trim(edEpocas.Text) ) ;

  WriteLn(IniFile,  SaveParams.BiasLayer1  );
  WriteLn(IniFile,  SaveParams.BiasLayer2  );

  WriteLn(IniFile,  SaveParams.WLayer1  );
  WriteLn(IniFile,  SaveParams.WLayer2  );

  Writeln ( IniFile , trim ( edMaxIteracoes.Text ) ) ;

  CloseFile(IniFile);



end;

procedure TForm1.btnSalvarMelhorRedeClick(Sender: TObject);
begin
  if not dlgSave.Execute then
    exit;

  SalvaIni ( dlgSave.FileName ) ;
end;

procedure TForm1.LoadIni(Path: String);
var
  IniFile : TextFile ;
  tmp     : String ;
begin

  AssignFile(IniFile, Path );
  Reset(IniFile);
  ReadLn(IniFile, tmp ) ;
  SaveParams.SizeInput  := StrToInt ( tmp ) ;
  ReadLn(IniFile, tmp  ) ;
  SaveParams.SizeLayer1 := StrToInt ( tmp );
  ReadLn(IniFile, tmp ) ;
  SaveParams.SizeLayer2 := StrToInt ( tmp );

  ReadLn(IniFile, tmp );
  SaveParams.Eta := StrToFloat ( tmp );
  ReadLn(IniFile,  tmp ) ;
  SaveParams.Momento := StrToFloat ( tmp );

  // Epoca
  ReadLn(IniFile,  tmp ) ;
  SaveParams.Epoca := StrToInt(tmp) ;

  ReadLn(IniFile,  SaveParams.BiasLayer1  );
  ReadLn(IniFile,  SaveParams.BiasLayer2  );

  ReadLn(IniFile,  SaveParams.WLayer1  );
  ReadLn(IniFile,  SaveParams.WLayer2  );

  Readln ( IniFile , tmp );
  SaveParams.MaxIt := StrToInt ( tmp );

  CloseFile(IniFile);

end;

procedure TForm1.actLoadNNExecute(Sender: TObject);
begin

  if not dlgOpen.Execute then
    Exit ;

  LoadIni ( dlgOpen.FileName  );

  edEta.Text              := FloatToStr ( SaveParams.Eta );
  edEpocas.Text           := IntToStr   ( SaveParams.Epoca );
  edMu.Text               := FloatToStr ( SaveParams.Momento );
  edTamanhoEntrada.Text   := IntToStr   ( SaveParams.SizeInput );
  edNLayer1.Text          := IntToStr   ( SaveParams.SizeLayer1 );
  edNLayer2.Text          := IntToStr   ( SaveParams.SizeLayer2 );
  edMaxIteracoes.Text     := IntToStr   ( SaveParams.MaxIt ) ;


  NN.CarregaBiasLayer1 ( SaveParams.BiasLayer1 );
  NN.CarregaBiasLayer2 ( SaveParams.BiasLayer2 );
  NN.CarregaWeightsLayer1 ( SaveParams.WLayer1 );
  NN.CarregaWeightsLayer2 ( SaveParams.WLayer2 );
  NN.Mu := SaveParams.Momento ;
  NN.Eta := SaveParams.Eta ;

  GetNNParams ;

end;

procedure TForm1.actTreinarExecute(Sender: TObject);
var
  X : TMatrix;

  T : TMatrix;

  j, jant : Double;

  melhorJValidacao : Double ;

  i    : Integer;

  Epoca : Integer;

  InFile,
  ValidFile : TStringList;

  TrainNumber,
  ValidNumber : Integer;

  line : string;

  Iterations : Integer;

  stopcount : Integer ;

const
  EPOCAS = 4;
  SIZE = 20;

begin
  Iterations := FIterations;
  X := TMatrix.Create(FSizeInput, 1);
  T := TMatrix.Create(FSizeLayer2, 1);

  InFile := TStringList.Create;
  ValidFile := TStringList.Create;

  InFile.LoadFromFile( IncludeTrailingBackslash ( ExtractFilePath ( ParamStr (0) ) ) + 'treino\infile.rni');
  TrainNumber := InFile.Count;

  ValidFile.LoadFromFile( IncludeTrailingBackslash ( ExtractFilePath ( ParamStr (0) ) ) + 'validacao\validfile.rni');
  ValidNumber := ValidFile.Count;
  melhorJValidacao := MaxDouble ;
  jant := 0;
  for Epoca := 0 to Iterations-1 do
    begin
      j := 0;
      for i := 0 to TrainNumber-1 do
        begin
          line := InFile[i];

          Delete(line, Pos('?', line), Length(Line));

          TFileOperator.CSVToVector(line, X);

          line := InFile[i];

          Delete(line, 1, Pos('?', line));

          TFileOperator.CSVToVector(line, T);

          NN.FeedForward ( X , T );
          NN.BackPropagation ( X );

          j := j + nn.J;
        end;      

      j := j/(TrainNumber);
      memoTreino.Lines.Add(IntToStr(ContadorGlobal) + ': ' + FloatToStr(j) );
      
      jant := j;

      j := 0;
      for i := 0 to ValidNumber-1 do
        begin
          line := ValidFile[i];

          Delete(line, Pos('?', line), Length(Line));

          TFileOperator.CSVToVector(line, X);

          line := ValidFile[i];

          Delete(line, 1, Pos('?', line));

          TFileOperator.CSVToVector(line, T);

          NN.FeedForward ( X , T );

          j := j + nn.J;
        end;

      j := j/(ValidNumber);

      if ( j < melhorJValidacao ) then
      begin
        melhorJValidacao := j ;
        stopcount := 0 ;
      end
      else
      begin
        Inc ( stopcount );
      end;

      memoValidacao.Lines.Add(IntToStr(ContadorGlobal) + ': ' + FloatToStr(j));


      NN.Update;

      Inc(ContadorGlobal);

      if (Epoca mod 10 = 0) then
        Application.ProcessMessages;

      //if (i > 0) and (Abs(jant-j)/j < 0.000001) then
      //Break;

    end;

  FreeAndNil(InFile);
  FreeAndNil(X);
  FreeAndNil(T);
end;

procedure TForm1.actNewNNExecute(Sender: TObject);
var
  tmp : Double ;
begin

  if Assigned ( NN ) then
    FreeAndNil ( NN );

  GetNNParams ;
  tmp := FEta/(FEpoca) ;
  NN  := TNeuralNetwork.Create ( FSizeInput , FSizeLayer1 , FSizeLayer2 , tmp , FMomento ) ;

end;


procedure TForm1.GetNNParams;
begin
    FSizeInput  := StrToIntDef ( edTamanhoEntrada.Text , 0) ;
    FSizeLayer1 := StrToIntDef ( edNLayer1.Text , 0 ) ;
    FSizeLayer2 := StrToIntDef ( edNLayer2.Text , 0) ;
    FEta        := StrToFloatDef ( edEta.Text , 0 )  ;
    FEpoca      := StrToIntDef ( edEpocas.Text , 0 ) ;
    FMomento    := StrToFloatDef ( edMu.Text , 0 )  ;
    FIterations := StrToIntDef ( edMaxIteracoes.Text , 0 ) ;
    ContadorGlobal := 0 ;
end;

procedure TForm1.actTestarExecute(Sender: TObject);
var
  X : TMatrix;

  T : TMatrix;


  i, h    : Integer;

  TestFile : TStringList;

  TestNumber : Integer;

  line : string;

  Maior : Double;
  MaiorIx : Integer;

  MatchLine : string;

begin
  X := TMatrix.Create(400, 1);
  T := TMatrix.Create(9, 1);

  TestFile := TStringList.Create;

  TestFile.LoadFromFile(IncludeTrailingBackslash ( ExtractFilePath ( ParamStr (0) ) ) + 'teste\testfile.rni');
  TestNumber := TestFile.Count;


  for i := 0 to TestNumber-1 do
    begin
      line := TestFile[i];

      Delete(line, Pos('?', line), Length(Line));

      TFileOperator.CSVToVector(line, X);

      line := TestFile[i];

      Delete(line, 1, Pos('?', line));

      TFileOperator.CSVToVector(line, T);

      NN.FeedForward ( X , T );

      Maior := -999999;
      MaiorIx := -1;
      for h := 0 to NN.Results.RowCount - 1 do
      begin
        if NN.Results[h,0] > Maior then
          begin
            Maior := NN.Results[h,0];
            MaiorIx := h;
          end;
        //memoTeste.lines.Add ( FloatToStr ( NN.Results[h,0] ) );
      end;

      for h := 0 to T.RowCount - 1 do
      begin
        if T[h, 0] = 1 then
          begin
            memoTeste.lines.Add ( IntToStr (MaiorIx + 1) + #9 + IntToStr (h+1) );
            Break;
          end;
      end;

    end;

end;

procedure TForm1.btnStrecherClick(Sender: TObject);
var
  bmp: TBitmap;

  arect      : TRect;

  i,
  c, r        : Integer;

  Line      : string;

  Filename  : string;

  InFileStringList  : TStringList;

  Files             : TStringList;


begin
  arect.TopLeft := Point(0, 0);
  arect.BottomRight := Point(20, 20);

  bmp := TBitmap.Create;

  Files := TFileOperator.ListFiles(ExtractFilePath(ParamStr(0)) + 'todas\', '*.bmp');
  
  for i := 0 to 0 do
    begin
      Filename := Files[i];

      bmp := TBitmap.Create;

      img.Stretch := false;
      img.AutoSize := true;

      img.Picture.LoadFromFile('todas\' + Filename);

      img.Stretch := True;
      img.AutoSize := False;

      img.Width := 20;
      img.Height := 20;

      bmp.Width := 20;
      bmp.Height := 20;

      img.Canvas.CopyRect(arect, bmp.Canvas, arect);

      bmp.SaveToFile('stretch\' + Filename);

      FreeAndNil(bmp);


    end;


end;

end.
